package com.zyl.file.websocket;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.concurrent.GlobalEventExecutor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

/**
 * @Author PJW 2023/2/2 16:14
 */
@Slf4j
@Component
@ChannelHandler.Sharable
public class WebSocketFrameHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    /**
     * 客户端集合
     */
    public static final ChannelGroup CHANNELS = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    /**
     * 客户端发消息会触发
     *
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
        //获取客户端传过来的消息，默认为当前用户id
        String content = msg.text();
        //把user和Channel关系存入map
        UserChannel.put(Long.parseLong(content), ctx.channel());
        log.info("初始用户id: {} ", content);
        //自测再打开
        //ctx.channel().writeAndFlush(new TextWebSocketFrame("斯内克，收到！"));
    }

    /**
     * 当客户端连接后，触发的方法
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        //把客户端添加到集合里面
        log.info("websocket-handlerAdded: {} ", "有客户端连接");
        CHANNELS.add(ctx.channel());
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        //断开连接后移除客户端
        log.info("websocket-handlerRemoved: {} ", "客户端断开连接");
        CHANNELS.remove(ctx.channel());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        //发生异常后关闭客户端。再移除
        cause.printStackTrace();
        ctx.channel().close();
        CHANNELS.remove(ctx.channel());
    }

    /**
     * 给指定用户发送消息
     *
     * @param userId
     * @param msg
     */
    public void send(Long userId, String msg) {
        Channel channel = UserChannel.get(userId);
        if (!ObjectUtils.isEmpty(channel)) {
            channel.writeAndFlush(new TextWebSocketFrame(msg));
        }
    }
}
